package servlets;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.LinkedList;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import controller.Course;
import controller.CourseSession;
import database.Connect;
import database.Queries;

/**
 * Servlet implementation class CourseServlet
 */
public class CourseServlet extends HttpServlet {
	Integer MaxSessionNum=4;
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public CourseServlet() {
        super();
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String action=request.getParameter("action");
		if(action.equals("add"))
		{
			addCourse(request, response);
			return;
		}
		if(action.equals("search"))
		{
			//TODO search with ajax
			String name=request.getParameter("name");
			response.sendRedirect("/salonmorandsmigi/course.jsp?name="+URLEncoder.encode(name,"UTF-8"));
			return;
		}
		if(action.equals("delete"))
		{
			deleteCourse(request, response);
			return;
		}
		if(action.equals("advanced"))
		{
			findCourses(request,response);
			return;
		}
		response.sendRedirect("/salonmorandsmigi/index.jsp");
		return;
	}

	/**
	 * 
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	private void findCourses(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		
		Connection conn=null;
		try {
			conn=Connect.getConnection();
			conn.setAutoCommit(false);
			String keywords=request.getParameter("name");
			String points = request.getParameter("points");
			String capacity = request.getParameter("capacity");
			String group = request.getParameter("groupnum");
			LinkedList<String> courses = Queries.findCourses(conn,keywords,points,capacity,group);
			String htmlToSend = turnToHtml(courses);
			PrintWriter out = response.getWriter();
			out.println(htmlToSend);
		} catch (SQLException e) {
			try {
				conn.rollback();
				response.sendError(500);
				e.printStackTrace();
			} catch (SQLException e1) {}
		}
		finally {
			if (conn!=null){
				try {
					conn.setAutoCommit(true);
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		
		
	}
	
	/**
	 * 
	 * @param courses
	 * @return
	 */
	private String turnToHtml(LinkedList<String> courses) {
		String result="";
		if (courses.isEmpty()){
			result+="<div class=\"rediv\"><h2>No Results</h2></div>";
			return result;
		}
		else {
			result+="<div class=\"searchlist\"><h2>Results</h2><ol>";
			for (String coursename : courses){
				result+="<li><a href=\"/salonmorandsmigi/course.jsp?name="+coursename+"\">"+coursename+"</a></li>";
			}
			result+="</ol></div>";
		}
		return result;
	}
	
	/**
	 * 
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	private void deleteCourse(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		String name=request.getParameter("name");
		Connection con = null;
		PreparedStatement stmt=null,stmt2=null,stmt3=null;
		try {
			con=Connect.getConnection();
			con.setAutoCommit(false);
			stmt=con.prepareStatement("" +
					"DELETE FROM courses WHERE coursename=?");
			stmt.setString(1,name);
			stmt.executeUpdate();
			//delete course from "registered" table
			stmt2 = con.prepareStatement("DELETE FROM registers WHERE coursename=?");
			stmt2.setString(1,name);
			stmt2.executeUpdate();
			// delete sessions of course
			stmt3 = con.prepareStatement("DELETE FROM sessions WHERE coursename=?");
			stmt3.setString(1,name);
			stmt3.executeUpdate();
			//if all is fine return ok
			con.commit();
			response.setStatus(200);
		} catch (SQLException e) {
			e.printStackTrace();
			response.sendError(500);
		    try {
		    	con.rollback();
				if (stmt!=null) stmt.close();
				if (stmt2!=null) stmt2.close();
				if (stmt3!=null) stmt3.close();
			} catch (SQLException e1) {
				e1.printStackTrace();
				return;
			}
		}
		finally{
			if (con!=null){
				try {
					con.setAutoCommit(true);
					con.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		response.sendRedirect("/salonmorandsmigi/courses.jsp");
		return;
	}

	/**
	 * 
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	private void addCourse(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		Connection con = null;
		
		String name=request.getParameter("name");
		String description=request.getParameter("description");
		Float pointsNum=Float.parseFloat(request.getParameter("credit"));
		Integer capacity=Integer.parseInt(request.getParameter("capacity"));
		Integer groupNumber=Integer.parseInt(request.getParameter("gnum"));
		String userName=request.getUserPrincipal().getName();
		int sessionNum=1;
		sessionNum = getSessionNumber(request, sessionNum);
		
		CourseSession[] sessions = validateAndGenerateSessions(request,sessionNum,name);
		if(sessions==null)
		{
			response.sendError(400);
			return;
		}
		
		//generate the course
		Course course=new Course(name,description,pointsNum,capacity,groupNumber,userName,sessions);
		
		//validate that the course is legal
		try {
			con = Connect.getConnection();
			con.setAutoCommit(false);
			LinkedList<Course>otherCourses=Queries.getCoursesFromGroup(con,groupNumber,userName);
			for (Course currentCourse:otherCourses)
			{
				if(course.addCollideWith(currentCourse))
				{
					response.sendError(402);
					return;
				}
			}
			//check if course exists
			if (Queries.isCourseExists(con, name)){
				response.sendError(405,"course exists");
				return;
			}
			addSessionsToDB(response, name, sessionNum, sessions, con);
			addCourseToDB(response, name, description, pointsNum, capacity,
					groupNumber, userName, con);
			con.commit();
		} catch (SQLException e1) {
			e1.printStackTrace();
			try {
				con.rollback();
				response.sendError(500);
				return;
			} catch (SQLException e) {
				e.printStackTrace();
				return;
			}
		}
		finally
		{
			if (con!=null) try {con.setAutoCommit(true);con.close();}catch (Exception ignore) {}
		}
	}

	/**
	 * 
	 * @param request
	 * @param sessionNum
	 * @return
	 */
	private int getSessionNumber(HttpServletRequest request, int sessionNum) {
		while(true)
		{
			if(request.getParameter("ses"+sessionNum)!=null)
			{
				sessionNum++;
				continue;
			}
			break;
		}
		return sessionNum-1;
	}
	
	/**
	 * 
	 * @param response
	 * @param name
	 * @param description
	 * @param pointsNum
	 * @param capacity
	 * @param groupNumber
	 * @param userName
	 * @param con
	 * @throws IOException
	 * @throws SQLException
	 */
	private void addCourseToDB(HttpServletResponse response, String name,
			String description, Float pointsNum, Integer capacity,
			Integer groupNumber, String userName, Connection con)
			throws IOException, SQLException {
			PreparedStatement stmt=con.prepareStatement(
					"INSERT INTO courses VALUES (" +
					"?,?,?,?,?,?);");
			stmt.setString(1,name);
			stmt.setString(2,description);
			stmt.setFloat(3,pointsNum);
			stmt.setInt(4,capacity);
			stmt.setInt(5,groupNumber);
			stmt.setString(6,userName);
			stmt.execute();
			if (stmt!=null){
				stmt.close();
			}
	}
	
	/**
	 * 
	 * @param response
	 * @param name
	 * @param sessionNum
	 * @param sessions
	 * @param con
	 * @throws IOException
	 * @throws SQLException
	 */
	private void addSessionsToDB(HttpServletResponse response, String name,
			int sessionNum, CourseSession[] sessions, Connection con)
			throws IOException, SQLException {
		for(int i=0;i<sessionNum;i++)
		{
				PreparedStatement stmt=con.prepareStatement(
						"INSERT INTO sessions VALUES (" +
						"?,?,?,?);");
				stmt.setString(1,name);
				stmt.setString(2,sessions[i].getDay());
				stmt.setInt(3,sessions[i].getStart());
				stmt.setInt(4,sessions[i].getEnd());
				stmt.execute();
				if (stmt!=null){
					stmt.close();
				}
		}
	}

	/**
	 * 
	 * @param request
	 * @param sessionNum
	 * @param courseName
	 * @return
	 * @throws IOException
	 */
	private CourseSession[] validateAndGenerateSessions(
			HttpServletRequest request,
			int sessionNum,String courseName) throws IOException {
		CourseSession[] sessions=new CourseSession[sessionNum];
		for(int i=1;i<=sessionNum;i++)
		{
			String day=request.getParameter("ses"+i);
			String start=request.getParameter("start"+i);
			String end=request.getParameter("end"+i);
			int IntStart = Integer.parseInt(start);
			int IntEnd = Integer.parseInt(end);
			if (IntStart>=IntEnd) return null;
			sessions[i-1]=new CourseSession(start,end,day,courseName);
			for(int j=0;j<i-1;j++)
			{
				if(sessions[j].collideWith(sessions[i-1]))
				{
					return null;
				}
			}
		}
		return sessions;
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request,response);
		return;
	}

}
